﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media.TextFormatting;
using System.Windows.Threading;
using Interfaces.CommonData;
using StockInfoFacade;
using StockInfoUI.Commands;

namespace StockInfoUI.MVVM
{

    internal class PivotCell
    {

        private string _Value;
        private string _ValueType;

        public string ValueType
        {
            get { return _ValueType; }
            set { _ValueType = value; }
        }

        public string Value
        {
            get { return _Value; }
            set { _Value = value; }
        }


        public override string ToString()
        {
            return string.Format("{0}:{1}", ValueType, Value);
        }
    }

    internal class MetricsTable : ObservableCollection<List<PivotCell>>,  INotifyPropertyChanged
    {

        private StockInfoFacade.StockInfoVM _facade;
        private readonly BackgroundWorker _bgwCorrelation = new BackgroundWorker();
        
        public MetricsTable()
        {
            string c = System.Configuration.ConfigurationSettings.AppSettings["ConnectionString"];
            string d = System.Configuration.ConfigurationSettings.AppSettings["dbname"];
            _facade = new StockInfoVM(c, d);
            PopulateDemoData();


            _bgwCorrelation.DoWork += AddRange;
            _bgwCorrelation.RunWorkerCompleted += CorrelationWorkerCompleted;
            _bgwCorrelation.WorkerReportsProgress = true;
            _bgwCorrelation.ProgressChanged += CorrelationWorkerChanged;
            ProgressVisibility = "Collapsed";

        }

        private void PopulateDemoData()
        {
            PivotCell delimeter = new PivotCell() { Value = "-", ValueType = "delimeter" };
            PivotCell C_AAPL = new PivotCell() { ValueType = "C", Value = "AAPL" };
            PivotCell C_ABT = new PivotCell() { ValueType = "C", Value = "ABT" };
            PivotCell C_ACN = new PivotCell() { ValueType = "C", Value = "ACN" };


            PivotCell R_AAPL = new PivotCell() { ValueType = "R", Value = "AAPL" };
            PivotCell R_ABT = new PivotCell() { ValueType = "R", Value = "ABT" };
            PivotCell R_ACN = new PivotCell() { ValueType = "R", Value = "ACN" };


            PivotCell V1 = new PivotCell() { ValueType = "V", Value = "1" };
            PivotCell V2 = new PivotCell() { ValueType = "V", Value = "0.1" };
            PivotCell V3 = new PivotCell() { ValueType = "V", Value = "0.2" };

            PivotCell V4 = new PivotCell() { ValueType = "V", Value = "0.1" };
            PivotCell V5 = new PivotCell() { ValueType = "V", Value = "1" };
            PivotCell V6 = new PivotCell() { ValueType = "V", Value = "0.2" };

            PivotCell V7 = new PivotCell() { ValueType = "V", Value = "0.1" };
            PivotCell V8 = new PivotCell() { ValueType = "V", Value = "0.2" };
            PivotCell V9 = new PivotCell() { ValueType = "V", Value = "1" };



            Add((new[] { delimeter, C_AAPL, C_ABT, C_ACN }).ToList());
            Add((new[] { R_AAPL, V1, V2, V3 }).ToList());
            Add((new[] { R_ABT,  V4, V5, V6 }).ToList());
            Add((new[] { R_ACN,  V7, V8, V9 }).ToList());

            
        }


        private RelayCommand _CalculateCorrelation;

        public RelayCommand CalculateCorrelation
        {
            get
            {
                _CalculateCorrelation = new RelayCommand(_bgwCorrelation.RunWorkerAsync);
                _CalculateCorrelation.IsEnabled = true;
                return _CalculateCorrelation;
            }
        }

        private void CorrelationWorkerCompleted(object Sender, RunWorkerCompletedEventArgs e)
        {
            CalcProgress = 0; //When finished loading reset the progress
            ProgressVisibility = "Collapsed";
        }

        private void CorrelationWorkerChanged(object Sender, ProgressChangedEventArgs e)
        {
            CalcProgress = e.ProgressPercentage;
            ProgressVisibility = "Overlay";
        }

        private int _calcProgress;

        public int CalcProgress
        {
            get { return this._calcProgress; }
            set
            {
                this._calcProgress = value;
                FirePropertyChanged("CalcProgress");
            }
        }

        private string _progressVisibility;

        public string ProgressVisibility
        {
            get { return _progressVisibility; }
            set
            {
                _progressVisibility = value;
                FirePropertyChanged("ProgressVisibility");
            }
        }

        private void AddRange(object Sender, DoWorkEventArgs e)
        {
            // Get data from data layer
            Dictionary<Stock, Dictionary<Stock, Decimal>> corrMatrix = _facade.GenerateCorrelationMatrix(_bgwCorrelation);
            var ll = TransformFromDictionary(corrMatrix);
            this.Clear();

            //_suspendCollectionChangeNotification = true;
            foreach (var l in ll)
            {
                Add(l);
            }
            //_suspendCollectionChangeNotification = false;
            //var arg = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, newItems[0]);
            //OnCollectionChanged(arg); 
        }


        private List<List<PivotCell>> TransformFromDictionary<TValue>(Dictionary<Stock, Dictionary<Stock, TValue>> source)
        {
            List<List<PivotCell>> fromDictionary = new List<List<PivotCell>>();

            Func<Stock, PivotCell> keyToPivotColumnHeader = new Func<Stock, PivotCell>(
                    d =>
                    new PivotCell() { Value = d.Ticker, ValueType = "C"}) ;
            Func<Stock, PivotCell> keyToPivotRowHeader = new Func<Stock, PivotCell>(
                    d =>
                    new PivotCell() { Value = d.Ticker, ValueType = "R" });
            Func<TValue, PivotCell> keyToPivotValue = new Func<TValue, PivotCell>(
                    v =>
                    new PivotCell() { Value = v.ToString(), ValueType = "V" });

            // add column headers
            List<Stock> lstKeys = source.Values.ToList().First().Keys.ToList();
            List<PivotCell> lstObjects = lstKeys.ConvertAll(new Converter<Stock, PivotCell>(keyToPivotColumnHeader));

            lstObjects.Insert(0, null);
            fromDictionary.Add(lstObjects);

            // add Values 
            source.Values.ToList().ForEach((elem) =>
            {
                var lstV = elem.Values.ToList();
                var lstVObj = lstV.ConvertAll(new Converter<TValue, PivotCell>(keyToPivotValue));
                // corner cell
                lstVObj.Insert(0, new PivotCell() { Value = "-"
                                                    , ValueType = "delimeter" });
                fromDictionary.Add(lstVObj);
            });

            // add row headers
            int i = 1;
            source.Keys.ToList().ForEach((elem) =>
            {
                fromDictionary[i][0] = keyToPivotRowHeader(elem);
                i++;
            });
            //ret[0][0] = "R1";
            return fromDictionary;
        }


        #region Disabling notify event. Doesn't really work

        public override event NotifyCollectionChangedEventHandler CollectionChanged;
        protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
        {
            NotifyCollectionChanged(e);
        }
        internal void NotifyCollectionChanged(NotifyCollectionChangedEventArgs e)
        {
            if (IsCollectionChangeSuspended)
            {
                return;
            }

            NotifyCollectionChangedEventHandler handler = CollectionChanged;
            if (handler != null)
            {
                if (Application.Current != null && !Application.Current.Dispatcher.CheckAccess())
                {
                    Application.Current.Dispatcher.Invoke(DispatcherPriority.DataBind, handler, this, e);
                }
                else
                {
                    handler(this, e);
                }
            }
        }

        private bool _suspendCollectionChangeNotification;
        private bool IsCollectionChangeSuspended
        {
            get { return _suspendCollectionChangeNotification; }
        }

        public event PropertyChangedEventHandler PropertyChanged;
        protected void FirePropertyChanged(String name)
        {
            PropertyChangedEventHandler handler = PropertyChanged;

            if (handler != null)
                handler(this, new PropertyChangedEventArgs(name));
        }

        #endregion

        
    }
}
